package service

import (
	"camera_app/entity"
	"fmt"
	"io"
	"math/rand"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
)

type PictureRepository struct {
	Picture *entity.Picture
	DB      *gorm.DB
}

var BUCKET_BASE_PATH = "/tmp/"

const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

func RandString(n int) string {
	b := make([]byte, n)
	rand.Seed(time.Now().UnixNano())
	for i := range b {
		b[i] = letterBytes[rand.Intn(len(letterBytes))]
	}
	return string(b)
}

func CheckOrCreate(path string) {
	if _, err := os.Stat(path); os.IsNotExist(err) {
		os.MkdirAll(path, 0777)
		return
	}
}

func CheckFileExist(path string) bool {
	if _, err := os.Stat(path); os.IsNotExist(err) {
		return false
	}
	return true
}

func (pr *PictureRepository) SavePictureToBucket(ctx *gin.Context) (bool, error) {
	file, err := ctx.FormFile("file")
	if err != nil {
		fmt.Println(err)
		return false, err
	}
	sessionUser, _ := ctx.Get("user")
	sessionUserEntity := sessionUser.(entity.User)
	fileName := file.Filename
	userDir := filepath.Join(BUCKET_BASE_PATH, sessionUserEntity.Username)
	dateString := time.Now().Format("2006-01-02")
	saveDir := filepath.Join(userDir, dateString)
	CheckOrCreate(saveDir)
	finalPath := filepath.Join(saveDir, fileName)
	for CheckFileExist(finalPath) {
		finalPath = filepath.Join(saveDir, RandString(10)+fileName)
	}
	if err := ctx.SaveUploadedFile(file, finalPath); err != nil {
		return false, err
	}
	pr.DB.Create(&entity.Picture{
		UserId:      sessionUserEntity.UserId,
		PictureName: fileName,
		PictureUrl:  finalPath,
		PictureTime: time.Now().Format("2006-01-02 15:04:05"),
		PictureDesc: ctx.PostForm("desc"),
		PictureTag:  ctx.PostForm("tag"),
	})
	return true, nil
}

func (pr *PictureRepository) SharePics(ctx *gin.Context) error {
	shareUser, _ := ctx.Get("user")
	shareUserEntity := shareUser.(entity.User)
	picIdString := ctx.PostForm("PicIdList")
	picIdList := strings.Split(picIdString, ",")
	var picList []entity.Picture
	// fmt.Println(picIdList)
	pr.DB.Model(&entity.Picture{}).Find(&picList, picIdList)
	// fmt.Println(picList)
	for _, pic := range picList {
		if pic.UserId != shareUserEntity.UserId {
			return fmt.Errorf("非法操作")
		}
	}
	err := CopyToShareDir(picList, shareUserEntity)
	if err != nil {
		return err
	}
	return nil

}

func (pr *PictureRepository) GetPicsByUser(ctx *gin.Context) ([]entity.Picture, error) {
	shareUser, _ := ctx.Get("user")
	shareUserEntity := shareUser.(entity.User)
	var picList []entity.Picture
	pr.DB.Model(&entity.Picture{}).Where("user_id = ?", shareUserEntity.UserId).Find(&picList)
	return picList, nil
}

func CopyToShareDir(picList []entity.Picture, shareUser entity.User) error {
	randomString := RandString(10)
	shareDir := filepath.Join(BUCKET_BASE_PATH, shareUser.Username, "share_"+randomString)
	CheckOrCreate(shareDir)
	for _, pic := range picList {
		src := pic.PictureUrl
		dst := filepath.Join(shareDir, pic.PictureName)
		if err := CopyFile(src, dst); err != nil {
			return err
		}
	}
	return nil
}
func CopyFile(src string, dst string) error {
	srcFile, err := os.Open(src)
	if err != nil {
		return err
	}
	defer srcFile.Close()
	dstFile, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer dstFile.Close()
	_, err = io.Copy(dstFile, srcFile)
	if err != nil {
		return err
	}
	err = dstFile.Sync()
	if err != nil {
		return err
	}
	return nil

}
